(function(){
	var SimpleStruct = {
		PageController:function(){
			//A basic function check. This will not catch things like Date()'s and such as those are technically at low level
			//functions themselves.
			var isFunction = function(funct){
				if(typeof(funct) == "function"){
					return true;
				}
				else{
					return false;
				}
			};
			
			//The content of the controls for the page
			//We have to seperate these out to prevent conflicting controls writing the same javascript to the page
			var controls = {};
			//The content of the page
			var content = {};
			//The objects on the page. This is useful if you have popups that need to access variables on the parent page
			var objects = {};
			//A reference to the parent object
			var me = this;
			
			this.addCtrl = function(ctrlId){
				//We add an empty json object to the controls object
				controls[ctrlId] = {};
			};
			
			this.addCtrlFunct = function(ctrlId, functId, funct){
				//First lets check if this is a function
				if(isFunction(funct)){
					//Make sure we at least have something as a name
					if(functId){
						//Also nee an id since this is a 2dimensional object
						if(ctrlId){
							controls[ctrlId][functId] = funct;
						}
						else{
							throw "ctrlId is required for addCtrlFunct";
						}
					}
					else{
						throw "functId is required for addCtrlFunct";
					}
				}
				else{
					throw "funct must be of type function to be added to added with addCtrlFunct";
				}
			};
			
			this.callCtrlFunct = function(ctrlId, functId, args){
				//This calls up the control function that we specified
				if(controls[ctrlId]){
					if(controls[ctrlId][functId]){
						return controls[ctrlId][functId](args);
					}
					else{
						throw "No function id " + functId +" exists inside the " + ctrlId +" control";
					}
				}
				else{
					throw "No control with id " + ctrlId + " exists inside the PageController";
				}
				
			};
			
			this.addFunct = function(name, funct){
				if(isFunction(funct)){
					if(name){
						content[name] = funct;
					}
					else{
						throw "Name is required for addFunct";
					}
				}
				else{
					throw "Funct must be of type function to be added to added with addFunct";
				}
			};
			//This calls a normal function of the page
			this.callFunct = function(name, args){
				if(content[name]){
					return content[name](args);
				}
				else{
					throw "No function named " + name +" exists inside the PageController";
				}
			};
			
			//Some object methods so we have our important objects accessable
			this.addObject = function(object){
				if(typeof object =='object'){
					objects[object.id] = object;
				}
				else{
					throw "Cannot add non-objects to the objects array";
				}
			};
			
			/* Getters */
			
			//This gets a function from the controller
			this.getFunct = function(name){
				if(content[name]){
					return content[name];
				}
				else{
					throw "No function named " + name +" exists inside the PageController";
				}
			};
			//This gets a control function from the control content object
			this.getCtrlFunct = function(ctrlId, functId){
				if(controls[ctrlId][functId]){
					return controls[ctrlId][functId];
				}
				else{
					throw "No function named " + functId +" exists control id "+ ctrlId + " inside the PageController";
				}
			};
			this.getObject = function(id){
				return objects[id];
			};
			
			this.getFuncts = function(){
				return content;
			};
			
			this.getControls = function(){
				return controls;
			};
			
			/* Testing tools */
			
			//Basic assertion
			this.assert = function(val, expectedVal, taggingText){
				//The tagging text allows the caller to define something to tag this generic assertion so they can identify it in their tests.
				var text = "";
				if (taggingText !== null && typeof taggingText !== "undefined"){
					text = taggingText;
				}
				if(expectedVal !== val){
					throw "Assertion failed. expected value: " + expectedVal + ", actual value: " + val + ". " + text;
				}
			};
			//Assert a function value
			this.assertFunctVal = function(id, expectedVal, args){
				//Go up to the parent and call it's function
				var assertionVal = me.callFunct(id, args);
				//Assert the values 
				me.assert(assertionVal, expectedVal, "Function id: " + id + ".");
			};
			//Run through all functions and perform the desired assertions
			this.assertAllFunctVal = function(args){
				//Go through all functions in content
				for(var x = 0; x < args.length; x++){
					var object = args[x];
					var id = object.id;
					var argu = object.args;
					var expectedVal = object.expected;
					//Go up to the parent and call it's function
					var assertionVal = me.callFunct(id, argu);
					//Assert the values 
					me.assert(assertionVal, expectedVal, "Function id: " + id + ".");
				}
			};
			//Assert a control funct val
			this.assertCtrlFunctVal = function(ctrlId, functId, expectedVal, args){
				//Go up to the parent and call it's function
				var assertionVal = me.callCtrlFunct(ctrlId, functId, args);
				//Assert the values 
				me.assert(assertionVal, expectedVal, "Control id: " + ctrlId + ", Function id: " + functId + ".");
			};
			
			this.assertAllCtrlFunctVal = function(args){
				//Go through all functions in content
				for(var x = 0; x < args.length; x++){
					var object = args[x];
					var ctrlId = object.ctrlId;
					var functId = object.functId;
					var argu = object.args;
					var expectedVal = object.expected;
					//Go up to the parent and call it's function
					var assertionVal = me.callFunct(ctrlId, functId, argu);
					//Assert the values 
					me.assert(assertionVal, expectedVal, "Control id: " + ctrlId + ", Function id: " + functId + ".");
				}
			};
		}
	}
	//Lets give access to this so everyone can
	window.Page = new SimpleStruct.PageController();
})();
